﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Controls.Primitives;
using System.ComponentModel;

namespace D3crft.Windows.UserControls {

    public partial class ucComboBoxAdvanced : UserControl {

        public delegate void delItemHandler(object oSender, string sSelectedItem);

        public event delItemHandler evItemSelected;
        public event TextChangedEventHandler evTextChanged;

        Border oBorder;
        DropShadowEffect oShadow;
        TextBox oTextBox;
        Label oArrow;
        ToggleButton oToggleButton;
        Popup oPopup;
        Grid oPopupGrid;

        string sText = "";
        List<string> slItems;
        List<Label> llLabels;

        int iHighlightedIndex = -1;
        int iSelectedIndex = -1;
        bool bAutoSelectionChanged = false;
        int iSelectionLength = 0;
        int iSelectionStart = 0;
        bool bLastSelectionChangeByUser = false;

        double dSetting_ItemHeight = 20.0;

        // ####################################################
        // #####    Class Initialization
        // ####################################################
        #region Class Initialization

        public ucComboBoxAdvanced() {
            InitializeComponent();
            slItems = new List<string>();
            llLabels = new List<Label>();

            oBorder = FindName("Border") as Border;
            oShadow = FindName("Shadow") as DropShadowEffect;
            oTextBox = FindName("TextBox") as TextBox;
            oArrow = FindName("Arrow") as Label;
            oToggleButton = FindName("ToggleButton") as ToggleButton;
            oPopup = FindName("Popup") as Popup;
            oPopupGrid = FindName("PopupGrid") as Grid;

            this.Loaded += new RoutedEventHandler(ev_Object_Loaded);

            oTextBox.TextChanged += new TextChangedEventHandler(ev_oTextBox_TextChanged);
            oTextBox.SelectionChanged += new RoutedEventHandler(ev_oTextBox_SelectionChanged);
            oTextBox.KeyDown += new KeyEventHandler(ev_oTextBox_KeyDown);
            oTextBox.GotFocus += new RoutedEventHandler(ev_oTextBox_GotFocus);
            oTextBox.LostFocus += new RoutedEventHandler(ev_oTextBox_LostFocus);


            oToggleButton.Click += new RoutedEventHandler(ev_oToggleButton_Click);
            DependencyPropertyDescriptor.FromProperty(ToggleButton.IsCheckedProperty, typeof(ToggleButton)).AddValueChanged(oToggleButton, new EventHandler(ev_oToggleButton_CheckedChanged));
            DependencyPropertyDescriptor.FromProperty(Popup.IsOpenProperty, typeof(Popup)).AddValueChanged(oPopup, new EventHandler(ev_oPopup_OpenChanged));
            DependencyPropertyDescriptor.FromProperty(ToggleButton.IsMouseOverProperty, typeof(ToggleButton)).AddValueChanged(oToggleButton, new EventHandler(ev_oToggleButton_MouseOverChanged));
        }

        #endregion

        // ####################################################
        // #####    Public Acccess
        // ####################################################
        #region Public Acccess

        public string Text {
            get { return sText; }
            set {
                if (sText.ToLower() != value.ToLower()) {
                    sText = value;
                    oTextBox.Text = sText;
                    iSelectedIndex = -1;
                    //do_RecommendTextInput();
                }
            }
        }

        public void AddItem(string sItem) {
            Label oTemp = new Label();

            oTemp.Name = "ILabel_" + slItems.Count.ToString();
            oTemp.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
            oTemp.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            oTemp.Margin = new Thickness(0.0, (double)slItems.Count * (dSetting_ItemHeight) - 1.0, 1.0, 0.0);
            oTemp.Height = dSetting_ItemHeight;
            oTemp.Width = this.Width - 22;
            oTemp.Content = sItem;
            oTemp.FontSize = 11.0;
            oTemp.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
            oTemp.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
            oTemp.Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;

            oTemp.Background = Brushes.Transparent;
            // register mouse events
            oTemp.MouseEnter += new MouseEventHandler(ev_ItemLabel_MouseEnter);
            oTemp.MouseDown += new MouseButtonEventHandler(ev_ItemLabel_MouseDown);
            oTemp.MouseUp += new MouseButtonEventHandler(ev_ItemLabel_MouseUp);

            slItems.Add(sItem);
            llLabels.Add(oTemp);
            oPopupGrid.Children.Add(oTemp);
            oPopupGrid.Height = (double)slItems.Count * dSetting_ItemHeight;
        }

        public void RemoveItem(string sItem) {

        }

        public void ClearItems() {

        }

        public bool IsValidItemSelected() {
            if (iSelectedIndex > -1) {
                return true;
            }
            return get_ExactTextMatch();
        }

        public void Focus() {
            this.oTextBox.Focus();
        }

        #endregion

        // ####################################################
        // #####    Events
        // ####################################################
        #region Events

        private void ev_Object_Loaded(object sender, EventArgs ea) {
            oToggleButton.Width = 20.0;
            oToggleButton.Height = this.Height;
            do_ReSetPopupLocation();
        }

        private void ev_oTextBox_TextChanged(object sender, TextChangedEventArgs ea) {
            this.sText = oTextBox.Text;
            if (evTextChanged != null) evTextChanged(this, null);
        }

        private void ev_oTextBox_SelectionChanged(object sender, EventArgs ea) {
            bool bTemp = false;
            return;
            if (iSelectionLength > 0) {
                // compare
                if ((iSelectionLength != oTextBox.SelectionLength) || (iSelectionStart != oTextBox.SelectionStart)) {
                    // change!
                    if (bAutoSelectionChanged) {
                        bTemp = true;
                    }
                }
            }
            else if (oTextBox.SelectionLength > 0) {
                // change!
                bTemp = true;
            }

            iSelectionLength = oTextBox.SelectionLength;
            if (iSelectionLength > 0) {
                iSelectionStart = oTextBox.SelectionStart;
            }

            if (bTemp) {
                bLastSelectionChangeByUser = false;
            }
            else {
                bLastSelectionChangeByUser = true;
            }
        }

        private void ev_oTextBox_KeyDown(object sender, KeyEventArgs ea) {
            return;
            bool bTemp = (ea.Key.Equals(System.Windows.Input.Key.Back)) ? true : false;
            if (bTemp) {
                MessageBox.Show("back");
            }
        }

        private void ev_oTextBox_GotFocus(object sender, EventArgs ea) {
            do_SetBorderColor();
        }

        private void ev_oTextBox_LostFocus(object sender, EventArgs ea) {
            do_SetBorderColor();
        }

        private void ev_oToggleButton_Click(object sender, EventArgs ea) {

        }

        private void ev_oToggleButton_CheckedChanged(object sender, EventArgs ea) {
            if (oToggleButton.IsChecked == true) {
                do_ShowPopup();
            }
            else {
                oPopup.IsOpen = false;
                if (iSelectedIndex > -1) set_LabelColorDefault(iSelectedIndex);
                if (iHighlightedIndex > -1) {
                    set_LabelColorDefault(iHighlightedIndex);
                    iHighlightedIndex = -1;
                }
            }
            do_SetButtonColor();
            do_SetBorderColor();
        }

        private void ev_oToggleButton_MouseOverChanged(object sender, EventArgs ea) {
            do_SetButtonColor();
        }

        private void ev_oPopup_OpenChanged(object sender, EventArgs ea) {
            if (oPopup.IsOpen == false) {
                if (oToggleButton.IsChecked == true) {
                    if (oToggleButton.IsMouseOver == false) {
                        oToggleButton.IsChecked = false;
                    }
                }
            }
        }

        private void ev_ItemLabel_MouseEnter(object sender, EventArgs ea) {
            int iIndex = get_IndexByLabel(sender as Label);

            if ((iSelectedIndex > -1) && (System.Windows.Input.Mouse.LeftButton == MouseButtonState.Pressed)) {
                if (iSelectedIndex == iIndex) return;
                // restore
                set_LabelColorDefault(iSelectedIndex);
                iSelectedIndex = iIndex;
                // select new
                set_LabelColorSelected(iIndex);
            }
            else {
                if (iHighlightedIndex > -1) {
                    // restore
                    set_LabelColorDefault(iHighlightedIndex);
                }
                if (iSelectedIndex == iIndex) return;
                iHighlightedIndex = iIndex;
                // highlight new
                set_LabelColorHighlighted(iIndex);
            }
        }

        private void ev_ItemLabel_MouseDown(object sender, EventArgs ea) {
            int iIndex = get_IndexByLabel(sender as Label);

            if (iSelectedIndex == iIndex) return;
            if (iSelectedIndex > -1) {
                // restore
                set_LabelColorDefault(iSelectedIndex);
                iSelectedIndex = -1;
            }

            if (iHighlightedIndex == iIndex) {
                set_LabelColorSelected(iIndex);
                iHighlightedIndex = -1;
                iSelectedIndex = iIndex;
            } else {
                if (iHighlightedIndex > -1) {
                    // restore
                    set_LabelColorDefault(iHighlightedIndex);
                    iHighlightedIndex = -1;
                }
                set_LabelColorSelected(iIndex);
                iSelectedIndex = iIndex;
            }
        }

        private void ev_ItemLabel_MouseUp(object sender, EventArgs ea) {
            int iIndex = get_IndexByLabel(sender as Label);

            oToggleButton.IsChecked = false;
            this.Text = slItems[iIndex];
            // event
            if (evItemSelected != null) evItemSelected(this, slItems[iIndex]);
        }

        #endregion

        // ####################################################
        // #####    Private Functions
        // ####################################################
        #region Private Functions

        private void do_SetButtonColor() {
            if (oToggleButton.IsChecked == true) {
                oArrow.Foreground = Brushes.White;
                oArrow.Background = Application.Current.FindResource("Gradient_PressedUC") as Brush;
            }
            else if (oToggleButton.IsMouseOver == true) {
                oArrow.Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
                oArrow.Background = Application.Current.FindResource("Gradient_HighlightedUC") as Brush;
            } else {
                oArrow.Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
                oArrow.Background = Application.Current.FindResource("Gradient_DefaultUC") as Brush;
            }
        }

        private void do_SetBorderColor() {
            if ((oToggleButton.IsChecked == true) || (oTextBox.IsFocused == true)) {
                oBorder.BorderBrush = Application.Current.FindResource("Brush_BlueHighlightedBorder") as Brush;
                oShadow.Color = (Color)Application.Current.FindResource("Color_BlueHighlightedBorder");
                oShadow.ShadowDepth = 1.75;
                oShadow.Opacity = 0.67;
                oToggleButton.BorderBrush = Application.Current.FindResource("Brush_BlueHighlightedBorder") as Brush;
            }
            else {
                oBorder.BorderBrush = Application.Current.FindResource("Brush_Border") as Brush;
                oShadow.Color = Colors.Black;
                oShadow.ShadowDepth = 1.0;
                oShadow.Opacity = 0.5;
                oToggleButton.BorderBrush = Application.Current.FindResource("Brush_Border") as Brush;
            }
        }

        private void do_ShowPopup() {
            do_ReSetPopupLocation();
            if (iSelectedIndex == -1) {
                do_TrySelectItemByText();
            }
            if (iSelectedIndex > -1) {
                set_LabelColorSelected(iSelectedIndex);
            }
            oPopup.IsOpen = true;
        }

        private void do_ReSetPopupLocation() {
            Point pLocation = this.PointToScreen(new Point(0, 0));
            oPopup.HorizontalOffset = pLocation.X;
            oPopup.VerticalOffset = pLocation.Y + this.Height;
            oPopupGrid.Width = this.Width - 20;
        }

        private int get_IndexByLabel(Label _oLabel) {
            int iTemp;
            string sTemp = _oLabel.Name.Split('_')[1];
            int.TryParse(sTemp, out iTemp);

            return iTemp;
        }

        private void set_LabelColorDefault(int iIndex) {
            llLabels[iIndex].Background = Brushes.Transparent;
            llLabels[iIndex].Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
        }

        private void set_LabelColorHighlighted(int iIndex) {
            llLabels[iIndex].Background = this.FindResource("Gradient_HighlightedUC") as Brush;
            llLabels[iIndex].Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
        }

        private void set_LabelColorSelected(int iIndex) {
            llLabels[iIndex].Background = this.FindResource("Gradient_SelectedUC") as Brush;
            llLabels[iIndex].Foreground = Application.Current.FindResource("Brush_PressedForeground") as Brush;
        }

        private void do_TrySelectItemByText() {
            int iTemp = get_BestTextMatch();

            if (iTemp >= 0) {
                // found!
                iSelectedIndex = iTemp;
                return;
            }
        }

        private bool get_ExactTextMatch() {
            if (Text == "") return false;
            for (int i = 0; i < slItems.Count; i++) {
                if (slItems[i].ToLower() == Text.ToLower()) {
                    // found!
                    iSelectedIndex = i;
                    return true;
                }
            }
            return false;
        }

        private int get_BestTextMatch() {
            if (Text == "") return -1;
            for (int i = 0; i < slItems.Count; i++) {
                if (slItems[i].ToLower().StartsWith(Text.ToLower())) {
                    // found!
                    return i;
                }
            }
            return -1;
        }

        private void do_RecommendTextInput() {
            int iTemp;
            string sTemp;

            iTemp = get_BestTextMatch();
            if (iTemp >= 0) {
                sTemp = slItems[iTemp].Substring(Text.Length);
                iTemp = Text.Length;
                bAutoSelectionChanged = true;
                Text = Text + sTemp;
                oTextBox.SelectionStart = iTemp;
                oTextBox.SelectionLength = sTemp.Length;
            }
        }

        #endregion

    }
}
